package com.hmdp.test.lifecycle.bean;

import cn.hutool.json.JSONUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.Serializable;

/**
 * 测试生命周期的 SpringBean
 *
 * @author lizhihui
 */
@Slf4j
@Getter
public class MyBean implements Serializable, InitializingBean, DisposableBean {

    private static final long serialVersionUID = 1L;

    @Value("${name:defaultName}")
    private String name;

    private Integer age;

    /**
     * 初始化方法
     *      1.添加了 @PostConstruct 注解的方法：
     *          在 bean 对象内添加 @PostConstruct 注解后即可实现初始化的功能，被 @PostConstruct 修饰的方法会在构造函数之后，init() 方法之前运行。有多个则会执行多次
     *          如果 spring 实现了 BeanPostProcessor 接口的 postProcessBeforeInitialization() 方法，也就是12的初始后置方法，那么 @PostConstruct 注解会失效
     *      2.实现 InitializingBean 接口
     *          spring 初始化方法之一，作用是在 BeanFactory 完成属性设置之后,执行自定义的初始化行为。执行顺序：在 initMethod 之前执行，在 @PostConstruct 之后执行
     *      3.在 @bean 注解上添加 initMethod 属性
     *          bean 配置文件属性 init-method 用于在 bean 初始化时指定执行方法，用来替代继承 InitializingBean 接口
     */
    @PostConstruct
    public void initPostConstruct() {
        // Servlet 初始化后执行
        log.error("17.初始化 - MyBean.initPostConstruct");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.error("17.初始化 - MyBean.afterPropertiesSet");
    }

    public void initMethod() {
        log.error("17.初始化 - MyBean.initMethod");
    }

    public MyBean() {
        log.error("2.实例化 - MyBean 无参构造函数执行 - this={}", JSONUtil.toJsonStr(this));
    }

    public MyBean(String name, Integer age) {
        this.name = name;
        this.age = age;
        log.error("?.MyBean 全参构造函数执行 - this={}", JSONUtil.toJsonStr(this));
    }

    public void setName(String name) {
        log.error("5.MyBean.setName - this={}", JSONUtil.toJsonStr(this));
    }

    @Value("${age:25}")
    public void setAge(Integer age) {
        // 用户属性指的是用 spring 的人自定义的bean对象属性，像 User、Student、Teacher 、UserService、IndexService 这类的对象都是自定义bean对象
        // 第5步主要给这类属性进行赋值操作，使用的是 AbstractAutowireCapableBeanFactory.populateBean() 方法进行赋值
        this.age = 25;
        log.error("5.用户属性注入 - MyBean.setAge - this={}", JSONUtil.toJsonStr(this));
    }

    public void working() {
        log.error("19.使用中 - MyBean.working - this={}", JSONUtil.toJsonStr(this));
    }

    @PreDestroy
    public void destroyPreDestroy() {
        log.error("20.销毁 - MyBean.destroyPreDestroy - this={}", JSONUtil.toJsonStr(this));
    }

    @Override
    public void destroy() throws Exception {
        log.error("20.销毁 - MyBean.destroy - this={}", JSONUtil.toJsonStr(this));
    }

    public void destroyMethod() {
        log.error("20.销毁 - MyBean.destroyMethod - this={}", JSONUtil.toJsonStr(this));
    }

}
